package cells;

import java.util.ArrayList;

import com.javable.cese.templates.AbstractAPModel;

/**
*
* Bachelor thesis at the Institute of Biomedical Engineering, 
* located at the UMIT/EWZ campus in Hall in Tyrol. <br><br>
*
* This is the abstract superclass of all cell voxels for a CA
* 
* @author Stefan Fuchs
*
*/
public abstract class AbstractVoxelCell {

	// Cell types
	
	public static final int TYPE_MYOCARD = 1;
	
	public static final int TYPE_AV_NODE = 2;
	
	public static final int TYPE_HIS_BUNDLE = 3;
	
	public static final int TYPE_PURKINJE = 4;
	
	public static final int TYPE_TAWARA = 5;
	
	public static final int TYPE_MISC = 99;
	
	private int x;
	
	private int y;
	
	private int z;
	
	protected ArrayList<Long> neighbourCellIndexList;
	
	public long cellIndex;
	
	private boolean junctionPoint;
	
	protected AbstractAPModel cellModel;
	
	public final int type;
	
	public AbstractVoxelCell(int x, int y, int z, 
			int type, int coordiante1D,  boolean junctionPoint) {
		this.cellIndex = (long) coordiante1D;
		this.neighbourCellIndexList = new ArrayList<Long>();
		this.x = x;
		this.y = y;
		this.z = z;
		this.junctionPoint = junctionPoint;
		this.type = type;
		//FIXME: uncomment
	//	initializeModel();
	}
	
	protected abstract void initializeModel();
	
	protected abstract void performCellStep(); 
	
	public AbstractAPModel getCellModel() {
		return cellModel;
	}
	
	public void setCellModel(AbstractAPModel cellModel) {
		this.cellModel = cellModel;
	}
	
	public int getX() {
		return x;
	}
	
	public int getY() {
		return y;
	}
	
	public int getZ() {
		return z;
	}
	
	public boolean isJunctionPoint() {
		return junctionPoint;
	}
	
	public void addNeigbourList(ArrayList<Long> neighbourList) {
		this.neighbourCellIndexList = neighbourList;
	}
	
	public long getNeighbourCount() {
		return (long) this.neighbourCellIndexList.size();
	}
	
	public ArrayList<Long> getNeighbours() {
		return this.neighbourCellIndexList;
	}
	
	public void addNeighbour(Long index) {
		this.neighbourCellIndexList.add(index);
	}
	
	public void removeNeighbour(Long index) {
		this.neighbourCellIndexList.remove(index);
	}
	
	public boolean isNeighbour(Long index) {
		return neighbourCellIndexList.contains(index);
	}
	
	public ArrayList<Long> add3DNeumanNeighours(int xDim, int yDim) {
		ArrayList<Long> newNeighourCellIndexList = new ArrayList<Long>();
		
		//x-dim
		neighbourCellIndexList.add(cellIndex + 1);
		neighbourCellIndexList.add(cellIndex - 1);
		
		//y-dim
		neighbourCellIndexList.add(cellIndex + xDim);
		neighbourCellIndexList.add(cellIndex - xDim);
		
		//indirect neighbours
		neighbourCellIndexList.add(cellIndex + 1 + xDim );
		neighbourCellIndexList.add(cellIndex + 1 - xDim );
		neighbourCellIndexList.add(cellIndex - 1 + xDim );
		neighbourCellIndexList.add(cellIndex - 1 - xDim );
		
		// z + 1;
		neighbourCellIndexList.add(cellIndex + xDim * yDim);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1);
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + xDim);
		neighbourCellIndexList.add(cellIndex + xDim * yDim - xDim);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1 + xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1 - xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1 + xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1 - xDim );
		
		// z - 1
		neighbourCellIndexList.add(cellIndex + xDim * yDim);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1);
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + xDim);
		neighbourCellIndexList.add(cellIndex + xDim * yDim - xDim);
		
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1 + xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim + 1 - xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1 + xDim );
		neighbourCellIndexList.add(cellIndex + xDim * yDim - 1 - xDim );
		
		return newNeighourCellIndexList;
	}
}
